package com.xframe.xdal.core.model.sqlbuilder;


import com.xframe.xdal.core.constant.*;
import com.xframe.xdal.core.domain.SysBaseEntity;
import com.xframe.xdal.core.exception.DalFrameException;
import com.xframe.xdal.core.model.ConditionValueCollection;
import com.xframe.xdal.core.model.DbSortCollection;
import com.xframe.xdal.core.model.SetWrapCollection;
import com.xframe.xdal.core.model.UpdateAttr;
import com.xframe.xdal.core.model.mapping.*;
import com.xframe.xdal.core.model.page.IPagerModel;
import lombok.AccessLevel;
import lombok.Data;
import lombok.Setter;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 功能描述:构件SQL的上下文对象
 *
 * @author xufeng
 * @version 1.0
 * @date 2022-09-26
 */
@Data
public class BuilderContext {

    public static boolean useDbObjectFlag = true;

    public static final String ALL = SysBaseEntity.FULL_DATA;

    @Setter(AccessLevel.NONE)
    private INameConvert nameConvert;

    /**
     * 表的映射信息
     */
    @Setter(AccessLevel.NONE)
    private ITableInfo tableInfo;

    /**
     * 当前的数据量(批量时用于限制批量执行的条数)
     */
    private int maxDataSize = 1000;

    /**
     * 数据库类型
     */
    @Setter(AccessLevel.NONE)
    private DataSourceTypeEnums dataSourceTypeEnums = DataSourceTypeEnums.MySql;


    /**
     * 查询条件
     */
    @Setter(AccessLevel.NONE)
    private ConditionValueCollection conditionValueCollection;

    /**
     * 排序对象
     */
    private DbSortCollection dbSortCollection;


    /**
     * 分页模型
     */
    private IPagerModel pagerModel;

    /**
     * 当前的数据
     */
    @Setter(AccessLevel.NONE)
    private DataWrap data;


    /**
     * 当前的占位符
     */
    @Setter(AccessLevel.NONE)
    private String colPlaceholder = "";

    /**
     * 查询的时候的引用名称列表
     */
    @Setter(AccessLevel.NONE)
    private Set<String> refList = new HashSet<>();

    /**
     * 更新的字段列表
     */
    @Setter(AccessLevel.NONE)
    private SetWrapCollection setWrapCollection = new SetWrapCollection();

    /**
     * 生成的SQL 是否有包含引用的列表
     */
    private boolean includeRefListFlag = false;

    /**
     * 引用表信息
     */
    private Map<String,ITableInfo> refTable = new HashMap<>();

    /**
     * 修改语句构造条件对象
     */
    @Setter(AccessLevel.NONE)
    private UpdateAttr updateAttr;

    public boolean getIncludeRefListFlag(){
        return this.includeRefListFlag;
    }



    public boolean includeBelongRefName(String name){
        return (refList.contains(ALL) || refList.contains(SysBaseEntity.BELONG_FULL_DATA)) ?true:refList.contains(name);
    }

    public boolean includeHasmanyRefName(String name){
        return (refList.contains(ALL) || refList.contains(SysBaseEntity.HASMANY_FULL_DATA)) ?true:refList.contains(name);
    }

    private void initColPlaceholder(){
        if(getDataSourceTypeEnums() == DataSourceTypeEnums.MySql){
            colPlaceholder = "`";
        }
        if (getDataSourceTypeEnums() == DataSourceTypeEnums.Oracle){
            colPlaceholder = "\"";
        }
    }


    public boolean hasDbSortCollection(){
        return this.dbSortCollection != null && this.dbSortCollection.size() > 0;
    }


    public BuilderContext(ITableInfo tableInfo) {
        this.tableInfo = tableInfo;
    }


    /**
     * 获取数据表非自动生成列映射集合
     *
     * @return List<IColumnMapping>
     */
    public List<IColumnMapping> findNotDbGenerated() {
        return this.getTableInfo().getColumnMappingList().stream().filter(columnMapping -> !columnMapping.getDbGeneratedFlag()).collect(Collectors.toList());
    }

    public static BuilderContext create(ITableInfo tableInfo,
                                        DataSourceTypeEnums dataSourceTypeEnums,Object data){
        return create(tableInfo,dataSourceTypeEnums,data,data.getClass(),
                null,null,null,null,null);
    }

    public static BuilderContext create(ITableInfo tableInfo,
                                        DataSourceTypeEnums dataSourceTypeEnums,Object data,UpdateAttr updateAttr){
        return create(tableInfo,dataSourceTypeEnums,data,data.getClass(),
                null,null,null,null,null,updateAttr);
    }

    public static BuilderContext create(ITableInfo tableInfo,
                                        DataSourceTypeEnums dataSourceTypeEnums,ConditionValueCollection whereCollection,SetWrapCollection setWrapCollection){
        return create(tableInfo,dataSourceTypeEnums,null,null,
                whereCollection,null,null,null,setWrapCollection);
    }


    /**
     * 构建单行数据sql 上下文对象
     *
     * @param tableInfo           表映射信息
     * @param dataSourceTypeEnums 数据库类型
     *
     * @return BuilderContext
     */
    public static BuilderContext create(ITableInfo tableInfo,
                                        DataSourceTypeEnums dataSourceTypeEnums,
                                        ConditionValueCollection conditionValueCollection,
                                        IPagerModel pagerModel,
                                        List<String> refList,
                                        DbSortCollection dbSortCollection) {
        return create(tableInfo,dataSourceTypeEnums,null,null,conditionValueCollection,pagerModel,refList,dbSortCollection,null);
    }


    public static BuilderContext create(ITableInfo tableInfo,
                                        DataSourceTypeEnums dataSourceTypeEnums,
                                        Object data,
                                        Class<?> dataType,
                                        ConditionValueCollection conditionValueCollection,
                                        IPagerModel pagerModel,
                                        List<String> refList,
                                        DbSortCollection dbSortCollection,
                                        SetWrapCollection setWrapCollection){
        return create(tableInfo,dataSourceTypeEnums,data,dataType,conditionValueCollection,pagerModel,refList,
                dbSortCollection,setWrapCollection,null);
    }
    /**
     * 构建单行数据sql 上下文对象
     *
     * @param tableInfo           表映射信息
     * @param dataSourceTypeEnums 数据库类型
     * @param data             数据行
     * @return BuilderContext
     */
    public static BuilderContext create(ITableInfo tableInfo,
                                        DataSourceTypeEnums dataSourceTypeEnums,
                                        Object data,
                                        Class<?> dataType,
                                        ConditionValueCollection conditionValueCollection,
                                        IPagerModel pagerModel,
                                        List<String> refList,
                                        DbSortCollection dbSortCollection,
                                        SetWrapCollection setWrapCollection,UpdateAttr updateAttr) {
        if (tableInfo == null || tableInfo.getColumnMappingList() == null || tableInfo.getColumnMappingList().size() == 0) {
            throw new DalFrameException(ErrorCode.TABLEINFO_NO_FIND,ErrorMsg.TABLEINFO_NO_FIND_MSG);
        }
        BuilderContext context = new BuilderContext(tableInfo);
        if(data != null) {
            if(data instanceof Collection){
                context.data = DataWrap.crateDataWrap((Collection)data,dataType);
            }else {
                context.data = DataWrap.crateDataWrap(data);
            }
        }
        context.dataSourceTypeEnums = dataSourceTypeEnums;
        context.conditionValueCollection = conditionValueCollection;
        if(context.conditionValueCollection == null){
            context.conditionValueCollection = new ConditionValueCollection();
        }
        if(refList != null && refList.size() > 0){
            for(int i = 0; i < refList.size(); i++){
                if(refList.get(i).equals(ALL)){
                    context.refList.clear();
                    context.refList.add(ALL);
                    break;
                }
                context.refList.add(refList.get(i));
            }
        }
        context.pagerModel = pagerModel;
        context.dbSortCollection = dbSortCollection;
        context.initColPlaceholder();
        context.nameConvert = NameConvertFactory.create(dataSourceTypeEnums);
        if(setWrapCollection != null) {
            context.setWrapCollection = setWrapCollection;
        }
        if(updateAttr != null) {
            context.updateAttr = updateAttr;
        }
        return context;
    }

    /**
     * 构建单行数据sql 上下文对象
     *
     * @param tableInfo           表映射信息
     * @param dataSourceTypeEnums 数据库类型
     * @return BuilderContext
     */
    public static BuilderContext create(ITableInfo tableInfo,
                                        DataSourceTypeEnums dataSourceTypeEnums) {
        if (tableInfo == null || tableInfo.getColumnMappingList() == null || tableInfo.getColumnMappingList().size() == 0) {
            throw new DalFrameException(ErrorCode.TABLEINFO_NO_FIND,ErrorMsg.TABLEINFO_NO_FIND_MSG);
        }

        BuilderContext context = new BuilderContext(tableInfo);

        context.dataSourceTypeEnums = dataSourceTypeEnums;
        context.initColPlaceholder();
        return context;
    }



    /**
     * 获取第一个数据表 主键列映射
     *
     * @return IColumnMapping
     */
    public IColumnMapping findPkFirst() {
        return this.getTableInfo().findPkFirst();
    }

    /**
     * 获取第一个数据表 版本号列映射
     *
     * @return IColumnMapping
     */
    public IColumnMapping findVer() {
        return this.getTableInfo().findVer();
    }

    /**
     * 获取所有数据表 不重复值列映射集合
     *
     * @return List<IColumnMapping>
     */
    public List<IColumnMapping> findUniqueKeyList() {
        return this.getTableInfo().findUniqueKeyList();
    }


    /**
     * 获取数据表所有可以更新的列映射集合
     *
     * @return List<IColumnMapping>
     */
    public List<IColumnMapping> findCanUpdateList() {
        return this.getTableInfo().findCanUpdateList();
    }

}
